#ifndef __TCP_SERVER__
#define __TCP_SERVER__

#include <iostream>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <memory.h>
#include <unistd.h>
#include <memory>
#include <sys/wait.h>
#include "threadpool/log.hpp"
#include "threadpool/task.hpp"
#include "threadpool/Thread.hpp"
#include "threadpool/ThreadPool.hpp"
#include <unordered_map>

// static void service(int sock,int port,std::string ip)
// {
//     char buffer[1024];
//     while(1)
//     {
//         //可以直接使用read和write
//         ssize_t s = read(sock,buffer,sizeof(buffer)-1);
//         if(s > 0)
//         {
//             buffer[s] = 0;
//             //printf("[%s]:[%d]-># %s",ip.c_str(),port,buffer);
//             std::cout << ip << ":" << port << "# " << buffer << std::endl;
//         }
//         else if(s == 0) //写端关闭连接
//         {
//             logMessage(NORMAL, "%s:%d shutdown, me too!", ip.c_str(), port);
//             break;
//         }
//         else
//         {
//             logMessage(ERROR,"read socket error, %d:%s", errno, strerror(errno));
//             break;
//         }
//         //写回数据
//         write(sock,buffer,sizeof buffer);
//     }
//     //关闭accpet返回的请求
//     close(sock);
// }

//标识线程的版本
static void service(int sock,int port,std::string ip,std::string name)
{
    //一直保持连接做任务，我们一般称之为“长连接”
    char buffer[1024];
    while(1)
    {
        //可以直接使用read和write
        ssize_t s = read(sock,buffer,sizeof(buffer)-1);
        if(s > 0)
        {
            buffer[s] = 0;
            //printf("[%s]:[%d]-># %s",ip.c_str(),port,buffer);
            std::cout << name << "|" << ip << ":" << port << "# " << buffer << std::endl;
        }
        else if(s == 0) //写端关闭连接
        {
            logMessage(NORMAL, "%s:%d shutdown, me too!", ip.c_str(), port);
            break;
        }
        else
        {
            logMessage(ERROR,"read socket error, %d:%s", errno, strerror(errno));
            break;
        }
        //写回数据
        write(sock,buffer,sizeof buffer);
    }
    //关闭accpet返回的请求
    close(sock);
}

static void change(int sock,int port,std::string ip,std::string name)
{
    char buffer[1024];
    while(1)
    {
        ssize_t s = read(sock,buffer,sizeof(buffer)-1);
        if(s > 0)
        {
            buffer[s] = 0;
            //printf("[%s]:[%d]-># %s",ip.c_str(),port,buffer);
            std::cout << name << "|" << ip << ":" << port << "# " << buffer << std::endl;
            std::string message = "";
            for(int i = 0;i < s;i++)
            {
                char c;
                if(islower(buffer[i]))
                    c = toupper(buffer[i]);
                else c = buffer[i];
                message += c;
            }
            write(sock,message.c_str(),message.size());
        }
        else if(s == 0) //写端关闭连接
        {
            logMessage(NORMAL, "%s:%d shutdown, me too!", ip.c_str(), port);
            break;
        }
        else
        {
            logMessage(ERROR,"read socket error, %d:%s", errno, strerror(errno));
            break;
        }
    }
    //关闭accpet返回的请求
    close(sock);
}

static void dict(int sock,int port,std::string ip,std::string name)
{
    char buffer[1024];
    std::unordered_map<std::string,std::string> mp = {
        {"orange","橘子"},
        {"day","日"},
        {"distinguish","区分"},
        {"apple","苹果"}
    };
    while(1)
    {
        ssize_t s = read(sock,buffer,sizeof(buffer)-1);
        if(s > 0)
        {
            buffer[s] = 0;
            //printf("[%s]:[%d]-># %s",ip.c_str(),port,buffer);
            std::cout << name << "|" << ip << ":" << port << "# " << buffer << std::endl;
            std::string message = "对不起没找到...";
            //TODO
            auto find = mp.find(buffer);
            if(find != mp.end())
                write(sock,find->second.c_str(),find->second.size());
            else
                write(sock,message.c_str(),message.size());
        }
        else if(s == 0) //写端关闭连接
        {
            logMessage(NORMAL, "%s:%d shutdown, me too!", ip.c_str(), port);
            break;
        }
        else
        {
            logMessage(ERROR,"read socket error, %d:%s", errno, strerror(errno));
            break;
        }
    }
    //关闭accpet返回的请求
    close(sock);
}

// struct ThreadData{
//     int _sock;
//     std::string _ip;
//     uint16_t _port;
// };

class TcpServer
{
private:    
    const static int gbacklog = 20;

    // static void* ThreadFunc(void* args)
    // {
    //     //告诉主线程别等我了
    //     //线程结束后（不会产生僵尸线程），其退出状态不由其他线程获取，而直接自己自动释放（自己清理掉PCB的残留资源）
    //     pthread_detach(pthread_self());
    //     //编译器隐式执行的任何类型转换都可以由static_cast显式完成
    //     ThreadData *td = static_cast<ThreadData *>(args);
    //     service(td->_sock,td->_port,td->_ip);
    //     delete td;

    //     return nullptr;
    // }

public:

    TcpServer(uint16_t port,std::string ip = "")
    :_port(port),_ip(ip),_listensock(-1),
    _threadPtr(ThreadPool<Task>::getInstance())
    {}
    bool initServer()
    {
        //这是一个文件描述符
        _listensock = socket(AF_INET,SOCK_STREAM,0);
        //判断是否创建失败
        if(_listensock < 0)
        {
            logMessage(FATAL,"crteate socket error,%d-%s",errno,strerror(errno));
            exit(2);
        }
        //获取套接字成功
        logMessage(NORMAL,"create socket success");
        
        //准备进行绑定
        struct sockaddr_in local;
        memset(&local,0,sizeof local);
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = _ip.empty()? INADDR_ANY : inet_addr(_ip.c_str());
        //新型网路地址转化函数inet_pton,/IPv6和IPv4都适用
        //inet_pton(AF_INET, _ip.c_str(), &local.sin_addr);
        //把ip地址转化为用于网络传输的二进制数值
        //inet_aton(_ip.c_str(), &local.sin_addr);
        if(bind(_listensock,(struct sockaddr*)&local,sizeof local) < 0)
        {
            logMessage(FATAL,"create bind failed,%d-%s",errno,strerror(errno));
            exit(1);
        }

        //因为TCP是面向连接的，当我们正式通信的时候，需要先建立连接
        //listen是告诉内核等待客户端的连接
        if(listen(_listensock,gbacklog) < 0)
        {
            logMessage(FATAL,"create listen failed,%d-%s",errno,strerror(errno));
            exit(3);
        }
        logMessage(NORMAL,"create listen success");

        return true;
    }

    void Start()
    {
        _threadPtr->run();
        while(1)
        {
            //输出型参数使用
            struct sockaddr_in src;
            socklen_t len = sizeof src;

            //如果服务器发送请求连接，就需要用accept接收
            int servicesock = accept(_listensock,(struct sockaddr*)&src,&len);
            if(servicesock < 0)
            {
                logMessage(ERROR, "accept error, %d:%s", errno, strerror(errno));
                continue;
            }
            //获取连接成功了
            uint16_t client_port = ntohs(src.sin_port);
            std::string client_ip = inet_ntoa(src.sin_addr);
            logMessage(NORMAL,"accept success [%s]:[%d]",client_ip.c_str(),client_port);
            
            //进行通信
            //version1 单进程版
            //传入一个accept的返回值（连接序号），和连接过来的客户端的端口、ip
            //service(servicesock,client_port,client_ip);

            //version2 多进程版
            // pid_t id = fork();
            // //子进程
            // if(id == 0)
            // {
            //     //子进程是来提供服务的，不需要监听，accept着就行了
            //     close(_listensock);
            //     service(servicesock,client_port,client_ip);
            //     exit(0); //僵尸状态
            // }
            // close(servicesock); //父进程关闭不会影响子进程、写时拷贝

            //2.1 多进程之子进程遗孤版
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     close(_listensock);
            //     if(fork() > 0) exit(1); //本身的子进程退出
            //     //孙子进程在执行任务，这个孙子进程又bash管理，是个孤儿
            //     service(servicesock,client_port,client_ip);
            //     exit(0); //执行完之后也要退
            // }
            // //waitpid(id,nullptr,1);
            // close(servicesock);

            //version3 多线程版
            //为了防止线程间共享td，我们需要在堆上开辟并传给线程，这样才是独一份
            // ThreadData* td = new ThreadData();
            // td->_ip = client_ip;
            // td->_port = client_port;
            // td->_sock = servicesock;
            // pthread_t tid;
            // //线程不用关闭相应的文件描述符(_listensock)，因为线程独自拥有文件描述符表
            // pthread_create(&tid,nullptr,ThreadFunc,td);

            //version4 线程池
            //Task task(servicesock,client_port,client_ip,service);
            //Task task(servicesock,client_port,client_ip,change);
            Task task(servicesock,client_port,client_ip,dict);
            _threadPtr->push_Task(task);
        }
    }

    ~TcpServer(){}
private:
    std::string _ip;
    uint16_t _port;
    int _listensock; //建立连接的套接字
    //线程池版本
    std::unique_ptr<ThreadPool<Task>> _threadPtr;
};


#endif